package core.swarm;

import utility.Utils;
import core.Mode;
import core.genetic.Population;
import core.genetic.selection.Selection;

public class SwarmLearningSelection  implements Selection {

	final int dimensions, popSize;
	final double vmax;
	Population pid;
	double[] bestSoFar;
//	double[][] v;
	double inw; // inertia weight
	int iteration = 0;

	final int close;
	final int mutCount;

	private final int learningCasesCount;
	private final double learningKoef;
	
	
	public SwarmLearningSelection(int close, int learningCasesCount, double learningKoef, int mutCount) {
		this.learningCasesCount =learningCasesCount;
		this.learningKoef = learningKoef;
		
		dimensions = Mode.mode.geneSize;
		popSize = Mode.mode.popSize;
		vmax = 2;
		inw = 0.9;
		this.close = close;
		this.mutCount = mutCount;

		bestSoFar = null;
		pid = null;
	}

	private boolean firstIter = true;

	@Override
	public void select(Population pop, double[] fitness) {

		inw = Math.max(0.4, 0.9 * (iteration / Mode.mode.nbGenerations));

		if (firstIter) {
			firstIter = false;
			pid = new Population(Mode.mode.geneSize);
			bestSoFar = fitness.clone();
			for (int i = 0; i < popSize; i++)
				pid.get(i).set(pop.get(i));			
		}
				
		for (int i = 0; i < popSize; i++) {							
			if (fitness[i] > bestSoFar[i]) {
				bestSoFar[i] = fitness[i]; 
				pid.get(i).set(pop.get(i));
			}
			
			
			int g = i;
			for(int k = -close;k<=close;k++) {
				int j = (i+k+fitness.length)%fitness.length;
				if (bestSoFar[j]>bestSoFar[g])
					g = j;
			}
			  
			double fi1 = Utils.random.nextDouble() * learningKoef;
			double fi2 = learningKoef-fi1;
			
			Mode.mode.brain.learn(pop.get(i), pid.get(i), fi1, learningCasesCount);
			Mode.mode.brain.learn(pop.get(i), pid.get(g), fi2, learningCasesCount);
			
		}		
		
		if (mutCount>0) {
			double[] pom = new double[fitness.length];
			for(int i = 0;i<fitness.length;i++)
				pom[i] = -fitness[i];
		
			double[] ver = Utils.calcCumulativeProb(pom,pom.length);
		
			for(int i = 0;i<mutCount;i++)
			{
				int z = Utils.randomW(ver);
				Mode.mode.mutation.mutate(pop.get(z));
			}
		
		}
		
		iteration++;
	}
}